package com.aop.test.ds.aspect;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import com.aop.test.ds.DataSourceSwitcher;
import com.aop.test.ds.annotation.DataSource;

@Aspect
@Component
public class DataSourceAspect {

	@Pointcut(value = "execution(* com.aop.test.service.*.*(..))")//切入点，针对service下面所有的方法
	//@Pointcut("@annotation(com.aop.test.ds.annotation.DataSource)")//切入点，针对所有这个DataSource注解的方法
	public void dsPointCut() {
	}

	/**
	 * 拦截目标方法，获取由@DataSource指定的数据源标识，设置到线程存储中以便切换数据源
	 * 
	 * @param point
	 * @throws Exception
	 */
	@Before(value = "dsPointCut()")
	public void intercept(JoinPoint point) throws Exception {
		Class<?> target = point.getTarget().getClass();
		MethodSignature signature = (MethodSignature) point.getSignature();
		// 默认使用目标类型的注解，如果没有则使用其实现接口的注解13
		for (Class<?> clazz : target.getInterfaces()) {
			resolveDataSource(clazz, signature.getMethod());
		}
		resolveDataSource(target, signature.getMethod());
	}

	/**
	 * 提取目标对象方法注解和类型注解中的数据源标识
	 * 
	 * @param clazz23
	 * @param method24
	 */
	private void resolveDataSource(Class<?> clazz, Method method) {
		try {
			Class<?>[] types = method.getParameterTypes();
			// 默认使用类型注解
			if (clazz.isAnnotationPresent(DataSource.class)) {
				DataSource source = clazz.getAnnotation(DataSource.class);
				DataSourceSwitcher.setDataSourceType(source.value());
			}
			// 方法注解可以覆盖类型注解
			Method m = clazz.getMethod(method.getName(), types);
			if (m != null && m.isAnnotationPresent(DataSource.class)) {
				DataSource source = m.getAnnotation(DataSource.class);
				DataSourceSwitcher.clearDataSourceType();
				DataSourceSwitcher.setDataSourceType(source.value());
				System.out.println("数据源设置成功：" + source.value());
			}
		} catch (Exception e) {
			System.out.println(clazz + ":" + e.getMessage());
		}
	}
	
	@After("dsPointCut()")
	public void after(JoinPoint point) {
		DataSourceSwitcher.clearDataSourceType();
	}

}